//-----------------------------------------------------------------------------
// Filename: RuntimeConfigBuilder.cs
//
// Description: Shell class for a basic runtime config file.
// Partially derived from Shawn Wildermuth's article 
// http://www.codeproject.com/csharp/runtime_eval.asp.
// 
// History:
// 11 Oct 2006	Aaron Clauson	Created.
//
// License: 
// Aaron Clauson
//-----------------------------------------------------------------------------

using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.IO;
using System.Net;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using Microsoft.CSharp;
using CN.Sys;
using CN.VoIP.Net.SIP;
using CN.VoIP.SIPServer;
using log4net;

#if UNITTEST
using NUnit.Framework;
#endif

namespace CN.VoIP.SIPServerCores.StatefulProxy
{
	public class RuntimeConfigBuilder
	{	
		private static ILog logger = AppState.logger;

		public Assembly BuildConfigAssembly(string referencedAssembliesPath, string configCode)
		{
			if(Regex.Match(configCode, @"System\.|Microsoft\.", RegexOptions.IgnoreCase).Success)
			{
				throw new ApplicationException("It is not permitted to use non-included namespace obejcts in the configuration method.");
			}
						
			DateTime compileStartTime = DateTime.Now;
			logger.Debug("Compiling user configuration.");
			
			ICodeCompiler comp = new CSharpCodeProvider().CreateCompiler();
			CompilerParameters cp = new CompilerParameters();

			cp.ReferencedAssemblies.Add("system.dll");
			cp.ReferencedAssemblies.Add("system.data.dll");
			cp.ReferencedAssemblies.Add("system.xml.dll");
			cp.ReferencedAssemblies.Add(referencedAssembliesPath + "CN.Sys.dll");
			cp.ReferencedAssemblies.Add(referencedAssembliesPath + "CN.VoIP.Net.dll");
			cp.ReferencedAssemblies.Add(referencedAssembliesPath + "CN.VoIP.SIPServerCores.dll");
			cp.ReferencedAssemblies.Add(referencedAssembliesPath + "log4net.dll");
			cp.GenerateExecutable = false;
			cp.GenerateInMemory = true;

			StringBuilder code = new StringBuilder();
			code.Append("using System; \n");
			code.Append("using System.Net; \n");
			code.Append("using System.Text.RegularExpressions; \n");
			code.Append("using System.Threading; \n");
			code.Append("using System.Xml; \n");
			code.Append("using CN.Sys; \n");
			code.Append("using CN.VoIP.Net.SIP; \n");
			code.Append("using CN.VoIP.SIPServer; \n");
			code.Append("using log4net; \n");
			code.Append("namespace CN.VoIP.SIPServerCores.StatefulProxy { \n");
			code.Append(" public class RuntimeSIPProxy : SIPProxyRuntimeConfig { \n");
			code.Append(" public RuntimeSIPProxy(string dialPlanExt) : base(dialPlanExt) {} \n");
			code.Append(" public override SwitchCallStruct SwitchCall(IPEndPoint local, IPEndPoint remote, SIPRequest sipRequest) { \n");

			code.Append(configCode);
			
			code.Append("} } }");

			CompilerResults cr = comp.CompileAssemblyFromSource(cp, code.ToString());
			if (cr.Errors.HasErrors)
			{
				StringBuilder error = new StringBuilder();
				error.Append("Error Compiling Expression: ");
				foreach (CompilerError err in cr.Errors)
				{
					error.AppendFormat("{0}\n", err.ErrorText);
				}
				throw new Exception("Error Compiling Expression: " + error.ToString());
			}
			
			Assembly sipRuntimeConfigAssemly = cr.CompiledAssembly;

			logger.Debug("SIP Proxy runtime config compilation complete, time taken " + DateTime.Now.Subtract(compileStartTime).TotalSeconds.ToString("0.##") + "s.");

			return sipRuntimeConfigAssemly;
		}
	}
}
